﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AcctrueWMS.Foundation.Common.Exception;
using System.Text.RegularExpressions;
using System.IO;
using AcctrueWMS.Foundation.Web;
using System.Reflection;
using  System.Data;
using System.Xml;
using AcctrueWMS.Foundation.Data;

namespace AcctrueWMS.Foundation.Common
{
    /// <summary>
    /// 参数替换的委托,委托给具体的类实现
    /// </summary>
    /// <param name="parameters"></param>
    /// <param name="model"></param>
    /// <param name="opttype"></param>
    public delegate void ProcessParameter(object[] parameters, DataModel model, string opttype);

    public delegate void ReplaceParameter(object[] parameters, DataTable dt, XmlDocument xmlDoc);


    public class CommandAnalyser
    {
        static Dictionary<string, InternalMethodImpl> implPool = new Dictionary<string, InternalMethodImpl>();

        //用以承载反射对象方法的内部实现类d
        public class InternalMethodImpl
        {
            public string AliasName
            {
                get;
                set;
            }

            public string TypeName
            {
                get;
                set;
            }

            public string MethodName
            {
                get;
                set;
            }
            public MethodInfo Method
            {
                get;
                set;
            }
            public string FullName
            {
                get;
                set;
            }

            public Type Type
            {
                get;
                set;
            }

            public object Instance
            {
                get;
                set;
            }

            public object[] Parameters
            {
                get;
                set;
            }
        }
        public struct SysExprFormat
        {
            public string Method;
            public string List;
            public string Type;
            public string Assembly;
            string fullName;
            public string FullName
            {
                get
                {
                    if (fullName == null)
                        fullName = string.Format("{0},{1},{2}", Method, Type, Assembly);
                    return fullName;
                }
            }
        }

        private DataModel model = null;
        private string renderMode = "";

        private DataTable dt = null;
        private XmlDocument xmlDoc = null;

        public CommandAnalyser()
        {
        }

        public CommandAnalyser(DataTable dt, XmlDocument xmlDoc)
        {
            this.dt = dt;
            this.xmlDoc = xmlDoc;
        }

        public CommandAnalyser(DataModel model, string renderMode)
        {
            this.model = model;
            this.renderMode = renderMode;
        }

        #region 处理反射信息
        static Dictionary<string, object> processorList = new Dictionary<string, object>();
        public ProcessParameter ProcessParameter;

        public ReplaceParameter ReplaceParameter;

        /// <summary>
        /// 由字符串得到符合类型的参数
        /// </summary>
        /// <param name="m"></param>
        /// <param name="paramstrs"></param>
        /// <returns></returns>
        private object[] GetRealParameters(MethodInfo m, string[] paramstrs)
        {
            List<object> parameters = new List<object>();
            ParameterInfo[] parameterInfo = m.GetParameters();
            for (int i = 0; i < paramstrs.Length; i++)
            {
                parameters.Add(ConvertParameterValue(parameterInfo[i].ParameterType, paramstrs[i]));
            }
            return parameters.ToArray();
        }

        private InternalMethodImpl GetMethodImpl(SysExprFormat sysExpr,string[] paramstrs)
        {
            string cacheKey = sysExpr.FullName + paramstrs.Length.ToString();
            InternalMethodImpl method = null;
            if (implPool.TryGetValue(cacheKey, out method))
            {
                return method;
            }
            lock (implPool)
            {
                //获取此类的方法，并添加到缓存，以减少重复读取，提高性能。
                Type t = Type.GetType(string.Format("{0},{1}", sysExpr.Type, sysExpr.Assembly));
                List<object> paramList = new List<object>();

                //重载方法，参数个数需不同
                MethodInfo refMethod=null;
                foreach (MethodInfo m in t.GetMethods())
                {                    
                    if (m.Name==sysExpr.Method&&m.GetParameters().Length == paramstrs.Length)
                    {
                        refMethod = m;                        
                        break;
                    }
                }
                if (refMethod == null)
                    throw new WMSException("找不到符合类型的方法");

                if (!implPool.ContainsKey(sysExpr.FullName))
                {
                    InternalMethodImpl impl = new InternalMethodImpl();
                    impl.TypeName = t.Name;
                    impl.Type = t;
                    impl.FullName = sysExpr.FullName+paramstrs.Length.ToString();
                    impl.Instance = GetInstance(t);
                    impl.MethodName = refMethod.Name;
                    impl.Method = refMethod;
                    implPool.Add(impl.FullName, impl);
                }
            }
            
            if (!implPool.ContainsKey(cacheKey))
                throw new WMSSysException("sys命令没有对应的实例！");
            return implPool[cacheKey];
        }
        static Dictionary<Type, object> instancePool = new Dictionary<Type, object>();
        /// <summary>
        /// 得到类的实例
        /// </summary>
        /// <param name="typName">完全限定名</param>
        /// <returns></returns>
        public object GetInstance(Type t)
        {
            if (!instancePool.ContainsKey(t))
            {
                lock (instancePool)
                {
                    if (!instancePool.ContainsKey(t))
                    {
                        instancePool.Add(t, Activator.CreateInstance(t));
                    }
                }
            }
            return instancePool[t];
        }

        /// <summary>
        /// 命令反射调用
        /// </summary>
        /// <param name="expr"></param>
        /// <returns></returns>
        public object Eval(string expr)
        {
            SysExprFormat sysExpr = ParseFullString(expr);
            string[] paramstrs = ParseParameters(sysExpr.List);
           
            InternalMethodImpl m = GetMethodImpl(sysExpr,paramstrs);
            object[] realParas=GetRealParameters(m.Method,paramstrs);
            //excel导入 反射需要添加分支
            if (expr.IndexOf("{xml}") > 0)
            {
                if (ReplaceParameter != null)
                    ReplaceParameter(realParas,dt,xmlDoc);
            }
            else  if (ProcessParameter != null)
                ProcessParameter(realParas, model, renderMode);
             try
             {
                 return m.Method.Invoke(m.Instance, realParas);
             }
             catch ( System.Exception ex)
             {             
                 throw new WMSBllException((ex.InnerException).Message);
             }
        }
        
        //根据程序集字符串反射实例
        public static object GetEntityByAssemblyName(string assemblyName)
        {
            if (string.IsNullOrEmpty(assemblyName)) return null;
            object entity = null;
            if (processorList.TryGetValue(assemblyName, out entity))
            {
                return entity;
            }
            lock (processorList)
            {
                if (!processorList.ContainsKey(assemblyName))
                {
                    //获取此类的方法，并添加到缓存，以减少重复读取，提高性能。
                    Type myType = Type.GetType(assemblyName);
                    entity = Activator.CreateInstance(myType, null);
                    processorList.Add(assemblyName, entity);
                }
            }
            if (!processorList.ContainsKey(assemblyName))
                throw new WMSSysException("反射未找到对应的类实例！");
            return processorList[assemblyName];
        }
        static Regex quoteReg = new Regex(@"quote{(?<quote>.*)}");
        //分析以逗号分隔的参数字符串，得到参数列表
        private string[] ParseParameters(string list)
        {
            List<string> parameters = new List<string>();
            if (string.IsNullOrEmpty(list.Trim()))
                return parameters.ToArray();

            //寻找参数中的非转义参数，并进行占位
            string quoteSymbol="***token_";
            MatchCollection mc = quoteReg.Matches(list);
            for(int i=0;i<mc.Count;i++)
            {
                list=list.Replace(mc[i].Value, quoteSymbol + i.ToString());
            }

            string[] paralist = list.Split(',');
            foreach (string str in paralist)
            {
                //如果是非转义参数
                if (str.StartsWith(quoteSymbol))
                {
                    string[] tokenArr = str.Split('_');
                    int index = int.Parse(tokenArr[1]);
                    parameters.Add(mc[index].Groups["quote"].Value);
                }
                else
                {
                    string para = str;
                    //如果含有首尾端含引号，则是标记为字符串
                    if (para.StartsWith("'") && para.EndsWith("'"))
                    {
                        para = para.Substring(1, str.Length - 2);
                    }
                    parameters.Add(para);
                }
            }
            return parameters.ToArray();
        }
        
        Regex fullReg = new Regex("(?<method>\\S+?)\\((?<list>.*)\\),(?<type>.*?),(?<assembly>.*)", RegexOptions.Compiled);
        Regex aliasReg = new Regex("#(?<alias>\\S*?)\\.(?<list>.*)", RegexOptions.Compiled);
        //分析含别名的表达式，并转换为实际的表达式
        private string ParseRealExpr(string expr)
        {
            string realExpr = expr;
            if (aliasReg.IsMatch(expr))
            {
                Match m = aliasReg.Match(expr);
                string alias = m.Groups["alias"].Value;
                string list = m.Groups["list"].Value;
                string fullName = AcctrueWMS.Foundation.Web.Runtime.ClsAliasManager.GetReal(alias).RealName.ToString();

                realExpr = string.Format("{0},{1}", list, fullName);
            }
            return realExpr;
        }
        //分析定义格式的系统命令格式，形如：方法(参数),类型，程序集
        private SysExprFormat ParseFullString(string expr)
        {
            expr = ParseRealExpr(expr);

            if (!fullReg.IsMatch(expr))
                throw new WMSSysException("不符合系统命令格式！");
            else
            {
                SysExprFormat sysExpr = new SysExprFormat();
                Match m = fullReg.Match(expr);
                sysExpr.Method = m.Groups["method"].Value;

                sysExpr.List = m.Groups["list"].Value;

                TextWriter tw = new StringWriter();
                //使用VTL语法，得到参数值
                Runtime.Context.Render.Render(sysExpr.List, tw);
                sysExpr.List = tw.ToString();
                tw.Close();

                sysExpr.Type = m.Groups["type"].Value;
                sysExpr.Assembly = m.Groups["assembly"].Value;
                return sysExpr;
            }
        }
        private object ConvertParameterValue(Type t,string str)
        {
            if (t == typeof(int))
                return int.Parse(str);
            if (t == typeof(decimal))
                return decimal.Parse(str);
            if(t==typeof(float))
                return float.Parse(str);
            if (t == typeof(DateTime))
                return DateTime.Parse(str);
            if (t == typeof(string))
                return str;
            return str;
        }
        #endregion
    }
}
